/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.koubei.imenu.websocket;

import com.imenu.WebApp;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;

/**
 *
 * @author yunzi
 */
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import org.eclipse.jetty.util.ajax.JSON;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocket.Outbound;
import org.eclipse.jetty.websocket.WebSocketServlet;

@WebServlet(name = "WebSocketChatServlet", urlPatterns = {"/websocket"})
public class WebSocketChatServlet extends WebSocketServlet {

    //private final Set<WebSocketClient> clients = new CopyOnWriteArraySet<WebSocketClient>();
    private final ConcurrentHashMap<YunTable, Set<WebSocketClient>> clients = new ConcurrentHashMap<YunTable, Set<WebSocketClient>>();
    //private final ConcurrentHashMap<YunTable, Set<ACourse>> orders = new ConcurrentHashMap<YunTable, Set<ACourse>>();

    @Override
    public void init() throws ServletException {
        super.init();
        WebApp webApp = new WebApp();
        webApp.setRoot(getServletContext().getContextPath());
        getServletContext().setAttribute("webApp", webApp);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws javax.servlet.ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        System.out.println("WebSocketChatServlet.doGet() request.getRequestURL() = " + request.getRequestURL());
        //getServletContext().getNamedDispatcher("default").forward(request,response);
        String menuIdParam = request.getParameter("menuId");
        System.out.println("WebSocketChatServlet.doGet() tableList menuIdParam = " + menuIdParam);
        System.out.println("WebSocketChatServlet.doGet() tableList menuNameParam = " + request.getParameter("menuName"));
        System.out.println("WebSocketChatServlet.doGet() tableList tableNameParam = " + request.getParameter("tableName"));
        System.out.println("WebSocketChatServlet.doGet() tableList typeParam = " + request.getParameter("type"));
        String typeParam = request.getParameter("type");
        if ("json".equals(typeParam)) {
            response.setContentType("application/json");
            System.out.println("WebSocketChatServlet.doGet() json type response.getContentType() = " + response.getContentType());
            response.setCharacterEncoding("utf-8");
            PrintWriter out = response.getWriter();
            List<Map> tables4Json = new ArrayList<Map>();
            synchronized (clients) {
                for (YunTable table : clients.keySet()) {
                    System.out.println("WebSocketChatServlet.doGet() tableList table = " + table);
                    int menuId = Integer.valueOf(menuIdParam);
                    if (table.getMenuId() == menuId) {
                        Map map = new TreeMap<String, Object>();
                        //map.put("id", course.getId());
                        map.put("menuId", table.getMenuId());
                        map.put("opener", table.getOpener());
                        map.put("tableName", table.getTableName());
                        map.put("status", table.getStatus());
                        tables4Json.add(map);
                    }
                }
            }
            System.out.println("WebSocketChatServlet.doGet() tables4Json 1 = " + tables4Json);
            net.sf.json.JSON json = JSONSerializer.toJSON(tables4Json);
            System.out.println("WebSocketChatServlet.doGet() tables4Json 2 = " + tables4Json);
            out.println(json);
            System.out.println("WebSocketChatServlet.doGet() tables4Json 3 = " + tables4Json);
            return;
        }
        if (menuIdParam == null) {
            request.setAttribute("errMsg", "客户端没有提供店家信息，服务器无法提供可加入点餐列表。");
            forward(request, response, "/tableList.jsp");
            return;
        } else {
            int menuId = Integer.valueOf(menuIdParam);
            List<YunTable> tableList = new ArrayList<YunTable>();
            synchronized (clients) {
                for (YunTable table : clients.keySet()) {
                    System.out.println("WebSocketChatServlet.doGet() tableList table = " + table);
                    if (table.getMenuId() == menuId) {
                        tableList.add(table);
                    }
                }
            }
            request.setAttribute("tableList", tableList);
            forward(request, response, "/tableList.jsp");
            return;
        }

    }

    private void forward(HttpServletRequest request, HttpServletResponse response, String url) throws ServletException, IOException {
        String path = url;
        System.out.println("WebSocketChatServlet.forward() path = " + path);
        getServletContext().getRequestDispatcher(path).forward(request, response);
    }

    @Override
    public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
        System.out.println("WebSocketChatServlet.doWebSocketConnect() request.getRequestURL() = " + request.getRequestURL());
        return new WebSocketClient();
    }

    class WebSocketClient implements WebSocket {

        YunTable yunTable;
        Outbound outbound;

        @Override
        public void onConnect(Outbound outbound) {
            this.outbound = outbound;
            //clients.add(this);
        }

        @Override
        public void onDisconnect() {
            //clients.remove(this);
            clients.get(yunTable).remove(this);
        }

        @Override
        public void onMessage(byte frame, String data) {
            JSONObject message = JSONObject.fromObject(data);
            String command = message.getString("command");
            System.out.println("WebSocketServlet.onMessage() command = " + command);
            System.out.println("WebSocketServlet.onMessage() this.yunTable = " + this.yunTable);
            System.out.println("WebSocketServlet.onMessage() clients = " + clients);

            if ("openTable".equals(command)) {
                ///if(this.yunTable == null){
                YunTable table = new YunTable(message.getInt("menuId"), message.getString("menuName"), message.getString("tableName"), message.getString("opener"));
                if (clients.containsKey(table)) {
                    for (YunTable temp : clients.keySet()) {
                        if (temp.equals(table)) {
                            this.yunTable = temp;
                            try {//如果自己已有桌，则相当于加入，也向客户端返回桌子状态
                                Map<String, Object> jsonMap = new HashMap<String, Object>();
                                jsonMap.put("command", "message");
                                jsonMap.put("message", this.yunTable.getStatusWithURLEncode());
                                this.outbound.sendMessage(frame, JSON.toString(jsonMap));
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } else {//有新的桌子建立，广播给所有客户端。
                    System.out.println("WebSocketServlet.onMessage() clients.put(yunTable, new CopyOnWriteArraySet<WebSocketClient>())");
                    this.yunTable = table;
                    clients.put(yunTable, new CopyOnWriteArraySet<WebSocketClient>());
                    this.broadcastMessage(frame, tableListMessage(message.getInt("menuId")));
                }
                //}
                System.out.println("open mode this.yunTable = " + this.yunTable);
                //if(clients.get(yunTable)==null){

                //}
                clients.get(yunTable).add(this);
                try {
                    this.outbound.sendMessage(frame, "{command:\"openDone\"}");
                } catch (Exception e) {
                    Log.warn(e);
                }
                System.out.println("Server received openTable command. clients.keySet() = " + clients.keySet());
            } else if ("join".equals(command)) {
                int menuId = message.getInt("menuId");
                String menuName = message.getString("menuName");
                String tableName = message.getString("tableName");
                String opener = message.getString("opener");
                System.out.println("command = join menuId = " + menuId + " menuName = " + menuName + " tableName=" + tableName + " opener =" + opener);
                System.out.println("Server received join command. clients.keySet() = " + clients.keySet());
                for (YunTable table : clients.keySet()) {
                    System.out.println("command = join current table = " + table);
                    if (table.getMenuId() == menuId && table.getTableName().equals(tableName) && table.getOpener().equals(opener)) {
                        System.out.println("command = join table equals done");
                        this.yunTable = table;
                        break;
                    }
                    System.out.println("command = join current this.yunTable = " + this.yunTable);
                }
                if (this.yunTable == null) {
                    System.out.println("join mode 没有找到被加入的桌子。");
                    this.yunTable = new YunTable(menuId, menuName, tableName, opener);
                    System.out.println("join mode this.yunTable = " + this.yunTable);
                }
                System.out.println("Server received join command. clients.keySet() = " + clients.keySet());
                if (clients.get(yunTable) == null) {
                    clients.put(yunTable, new CopyOnWriteArraySet<WebSocketClient>());
                }
                System.out.println("clients.get(yunTable).add(this) before clients.get(yunTable)=" + clients.get(yunTable));
                clients.get(yunTable).add(this);
                System.out.println("clients.get(yunTable).add(this) after clients.get(yunTable)=" + clients.get(yunTable));
                try {//加入成功，即返回当前桌状态
                    Map<String, Object> jsonMap = new HashMap<String, Object>();
                    jsonMap.put("command", "message");
                    jsonMap.put("message", this.yunTable.getStatusWithURLEncode());
                    this.outbound.sendMessage(frame, JSON.toString(jsonMap));
                } catch (Exception e) {
                    Log.warn(e);
                }
            } else if ("dish".equals(command)) {
                System.out.println("Server received dish command. data = " + data);
                System.out.println("Server received dish command. clients.keySet() = " + clients.keySet());
                this.yunTable.order(message.getInt("courseId"), message.getInt("price"));
                this.broadcastTableStatus(frame);
            } else if ("removeCourse".equals(command)) {
                System.out.println("Server received dish command. data = " + data);
                yunTable.remove(message.getInt("orderedCourseId"));
                Map<String, Object> jsonMap = new HashMap<String, Object>();
                jsonMap.put("command", "message");
                jsonMap.put("message", this.yunTable.getStatusWithURLEncode());
                this.broadcastTableStatus(frame);
            } else if ("orderList".equals(command)) { //将全部菜品发往客户端，用于编辑
                Map<String, Object> jsonMap = new HashMap<String, Object>();
                jsonMap.put("command", "orderList");
                StringBuilder courses = new StringBuilder();
                Map<Integer, YunTable.Course> ordered = this.yunTable.getOrdered();
                synchronized (ordered) {
                    Iterator<Map.Entry<Integer, YunTable.Course>> it = ordered.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry<Integer, YunTable.Course> entry = it.next();
                        courses.append(":").append(entry.getKey()).append(",").append(entry.getValue().getCourseId());
                    }
                }
                if (ordered.size() > 0) {
                    jsonMap.put("courses", courses.substring(1));//已点菜肴，传courseId和orderedCourseId到客户端，删除时，将orderedCourseId回传至服务器
                }
                System.out.println("WebSocketChatServet.client.onMessage() orderList courses =" + courses);
                try {
                    this.outbound.sendMessage(frame, JSON.toString(jsonMap));
                } catch (Exception e) {
                    Log.warn(e);
                }
            } else if ("finishOrder".equals(command)) {
                Map<String, Object> jsonMap = new HashMap<String, Object>();
                jsonMap.put("command", "message");
                jsonMap.put("message", "菜单已经提交，点菜结束。");
                broadcastMessage(frame, JSON.toString(jsonMap));
                yunTable.getOrdered().clear();
                clients.remove(yunTable);
            } else if ("tableList".equals(command)) {
                System.out.println("WebSocketChatServet.client.onMessage() tableList command ");
                int menuId = message.getInt("menuId");
                try {
                    System.out.println("WebSocketChatServet.client.onMessage() this.outbound.sendMessage() ");
                    this.outbound.sendMessage(frame, tableListMessage(menuId));
                } catch (Exception e) {
                    Log.warn(e);
                }
            }
        }
        
        private String tableListMessage(int menuId) {
            Map<String, Object> jsonMap = new HashMap<String, Object>();
            List<Map> tables4Json = new ArrayList<Map>();
            synchronized (clients) {
                for (YunTable table : clients.keySet()) {
                    System.out.println("WebSocketChatServet.client.onMessage() tableList table = " + table);

                    if (table.getMenuId() == menuId) {
                        Map map = new TreeMap<String, Object>();
                        //map.put("id", course.getId());
                        map.put("menuId", table.getMenuId());
                        map.put("opener", table.getOpener());
                        map.put("tableName", table.getTableName());
                        map.put("status", table.getStatus());
                        tables4Json.add(map);
                    }
                }
            }
            jsonMap.put("tableList", tables4Json);
            jsonMap.put("command", "tableList");
            return JSON.toString(jsonMap);
        }

        public void broadcastTableStatus(byte frame) {
            Map<String, Object> jsonMap = new HashMap<String, Object>();
            jsonMap.put("command", "message");
            jsonMap.put("message", this.yunTable.getStatusWithURLEncode());
            broadcastMessage(frame, JSON.toString(jsonMap));
        }

        public void broadcastMessage(byte frame, String message) {
            for (WebSocketClient client : clients.get(yunTable)) {
                try {
                    System.out.printf("WebSocketServlet.broadcastMessage() yunTable="+yunTable+" client.yunTable="+client.yunTable);
                    client.outbound.sendMessage(frame, message);
                } catch (IOException e) {
                    Log.warn(e);
                }
            }
        }

        @Override
        public void onMessage(byte arg0, byte[] arg1, int arg2, int arg3) {
        }

        @Override
        public void onFragment(boolean arg0, byte arg1, byte[] arg2, int arg3,
                int arg4) {
        }
    }
}